/*
 *  Blazon: A user datagram protocol re-braodcasting daemon.
 *  log.c: Logging functions.
 *
 *  Copyright 2012 Blazon development team
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "std-include.h"

#include <stdarg.h>		/* va_list functions */
#include <time.h>		/* localtime() strftime() */

#include "log.h"
#include "blazon.h"

static int log_level = LOG_STDOUT;
static FILE *logfile = NULL;

void log_main(const char *format, ...);
void log_err(const char *format, ...);
void log_warn(const char *format, ...);
void log_info(const char *format, ...);
void log_debug(const char *format, ...);


static bool
verify_log_access(const char *file)
{
	if (access(file, F_OK) == 0)
	{
		if (access(file, W_OK) == -1)
		{
			log_err("Cannot write to logfile: %s", file);
			return false;
		}
	}

	return true;
}


/* Returns success of failure to the caller so we can die() if, for some
 * reason, logging cannot be set up. */
bool
logging_open(const char *filepath, int level)
{
	if (!verify_log_access(filepath))
		return false;

	logfile = fopen(filepath, "a");

	if (logfile == NULL)
		return false;

	log_level = level;

	return true;
}


bool
logging_reopen(const char *filepath, int level)
{
	FILE *templog = NULL;

	if (!verify_log_access(filepath))
		return false;

	templog = fopen(filepath, "a");
	if (templog == NULL)
		return false;

	log_level = level;
	fclose(logfile);
	logfile = templog;

	return true;
}


void
logging_close(void)
{
	if (logfile != NULL)
		fclose(logfile);

	logfile = NULL;
	log_level = 0;
}


/* Log lines that have already had their va_list captured. */
static void
va_list_log(const char *pri, const char *format, va_list ap)
{
	char datestr[DATETIME_SIZE];
	time_t ltime = CURRENT_TIME;
	struct tm *lt_now = localtime(&ltime);

	/* Fetch and format local time into something nice. */
	strftime(datestr, DATETIME_SIZE, "%Y-%m-%d %H:%M:%S", lt_now);

	if (log_level == LOG_STDOUT)
	{
		vfprintf(stderr, format, ap);
		fprintf(stderr, "\n");
		fflush(stderr);
	}
	else
	{
		fprintf(logfile, "%s %s ", datestr, pri);
		vfprintf(logfile, format, ap);
		fprintf(logfile, "\n");
		fflush(logfile);
	}
}


void
log_main(const char *format, ...)
{
	va_list args;

	if (log_level < LOG_MAIN)
		return;

	va_start(args, format);
	va_list_log("LOG:", format, args);
	va_end(args);
}


void
log_err(const char *format, ...)
{
	va_list args;

	if (log_level < LOG_ERR)
		return;

	va_start(args, format);
	va_list_log("ERROR:", format, args);
	va_end(args);
}


void
log_warn(const char *format, ...)
{
	va_list args;

	if (log_level < LOG_WARN)
		return;

	va_start(args, format);
	va_list_log("WARN:", format, args);
	va_end(args);
}


void
log_info(const char *format, ...)
{
	va_list args;

	if (log_level < LOG_INFO)
		return;

	va_start(args, format);
	va_list_log("INFO:", format, args);
	va_end(args);
}


void
log_debug(const char *format, ...)
{
	va_list args;

	if (log_level < LOG_DEBUG)
		return;

	va_start(args, format);
	va_list_log("DEBUG:", format, args);
	va_end(args);
}
